'''
////////////////////////////////////////////////////////////////////
//                            _ooOoo_                             //
//                           o8888888o                            //
//                           88" . "88                            //
//                           (| ^_^ |)                            //
//                           O\  =  /O                            //
//                        ____/`---'\____                         //
//                      .'  \\|     |//  `.                       //
//                     /  \\|||  :  |||//  \                      //
//                    /  _||||| -:- |||||-  \                     //
//                    |   | \\\  -  /// |   |                     //
//                    | \_|  ''\---/''  |   |                     //
//                    \  .-\__  `-`  ___/-. /                     //
//                  ___`. .'  /--.--\  `. . ___                   //
//                ."" '<  `.___\_<|>_/___.'  >'"".                //
//              | | :  `- \`.;`\ _ /`;.`/ - ` : | |               //
//              \  \ `-.   \_ __\ /__ _/   .-` /  /               //
//        ========`-.____`-.___\_____/___.-`____.-'========       //
//                             `=---='                            //
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^      //
//        佛祖保佑             永无BUG              永不修改         //
////////////////////////////////////////////////////////////////////
'''


import sys
import cv2 as cv
import torch
from PyQt5.QtWidgets import QMainWindow, QApplication, QTextEdit
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import QTimer, QThread, pyqtSignal

from main_window1 import Ui_MainWindow

import time
import serial
import struct
import glob

# 使用glob.glob查找以/dev/ttyUSB开头的所有串口
# 这将返回一个列表，其中包含匹配的串口名称
available_ports = glob.glob('/dev/ttyUSB*')

if not available_ports:
    print("没有找到可用的串口。")
else:
    # 选择第一个匹配的串口（你可以根据需要修改选择逻辑）
    selected_port = available_ports[0]
    print(selected_port)

serial_port = serial.Serial(
    port=selected_port,
    baudrate=38400,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    timeout=1
)

A = 0x00

Recycle = struct.pack('BBBB BBBB', 0x77, 0x01, A, A, A, A, A, A)

Harmful = struct.pack('BBBB BBBB', 0x77, 0x02, A, A, A, A, A, A)

Kitchen = struct.pack('BBBB BBBB', 0x77, 0x03, A, A, A, A, A, A)

Others = struct.pack('BBBB BBBB', 0x77, 0x04, A, A, A, A, A, A)

# MaxDet = struct.pack('BBBB BBBB', 0x88, A, A, A, A, A, A, A)

def convert2QImage(img):
    height, width, channel = img.shape
    return QImage(img, width, height, width * channel, QImage.Format_RGB888)


def sent_command(com):
    serial_port.write(com)

def read_mess():
    # 读取一个字节的串口数据
    data = serial_port.read(1)

    # 将接收的数据转换为十六进制
    received_value = int.from_bytes(data, byteorder='big', signed=False)

    return received_value

R = -8
H = -16
K = -12
O = -20
# x1 = 0x00
# x2 = 0x00  
# y1 = 0x00  
# y2 = 0x00  
# kind = 0x00  

# PickUp = struct.pack('BBBB BBBB', 0x55, kind, A, x1, x2, A, y1, y2)

class VideoThread(QThread):
    frame_processed = pyqtSignal(QImage)
    text_processed = pyqtSignal(str)
    x1_y1_updated = pyqtSignal(int, int, int, int, int)  # 新的信号用于发送x1, x2, y1, y2, kind的值
    maxdet_triggered = pyqtSignal()

    def __init__(self, model):
        super().__init__()
        self.model = model
        # global x1,x2,y1,y2
        x1 = 0x00
        x2 = 0x00  
        y1 = 0x00  
        y2 = 0x00  
        kind = 0x00  
        A = 0x00
        PickUp = struct.pack('BBBB BBBB', 0x55, kind, A, x1, x2, A, y1, y2)

    def run(self):
        self.cont = 0
        global R, H, K, O, PickUp
        self.det = cv.VideoCapture(0)
        self.det.set(cv.CAP_PROP_FRAME_WIDTH, 1280)
        self.det.set(cv.CAP_PROP_FRAME_HEIGHT, 960)
        print(self.det.get(3), self.det.get(4), self.det.get(cv.CAP_PROP_FPS), self.det.get(cv.CAP_PROP_EXPOSURE))
        
        while True:
            ret, frame = self.det.read()
            if not ret:
                print("Error: Unable to read frame.")
                self.det.release()
                break
            else:
                height, width, _ = frame.shape

                # # 计算裁剪的起始坐标
                x = (width - 640) // 2
                y = (height - 560) // 2

                # 进行中心裁剪
                frame = frame[y:y + 640, x:x + 640]

                frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
                results = self.model(frame)
                image = results.render()[0]
                # df = results.pandas().xyxy[0]
                df = results.pandas().xyxy[0].sort_values(by='class', ascending=True)
                self.frame_processed.emit(convert2QImage(image))

                detection_texts = []
                # print(df)

                max_num = len(df)
                # if max_num > 1:

                # print(f"max_num:{max_num}")
                for i, row in df.iterrows():
                    xmin = int(row['xmin'])
                    ymin = int(row['ymin'])
                    xmax = int(row['xmax'])
                    ymax = int(row['ymax'])
                    class_id = int(row['class'])
                    labels = row['name']

                    if max_num > 1:     # 多个垃圾

                        x_center_px = int((xmin+xmax)/2)
                        y_center_px = int((ymin+ymax)/2)

                        px2mm = 5/12           # 1 px is 5/12 mm
                        px2psc = 2560/147      # 1 px is 2560/147 psc  12 px is 5 mm in 1280*960(1280*720)

                        x_length = int(xmax-xmin)
                        y_length = int(ymax-ymin)

                        if x_length > y_length:
                            angle = 0x02
                            px2duo = hex(int((y_length*px2mm - 315.2) / (-3.23))+7)
                        else:
                            angle = 0x01
                            px2duo = hex(int((x_length*px2mm - 315.2) / (-3.23))+7)

                        # if int(px2duo,16) == 0x66 or int(px2duo,16) == 0x77:
                        #     int(px2duo,16) -= 1

                        # x_center_psc = int(x_center_px * px2psc)+4096*1.2
                        # y_center_psc = int(y_center_px * px2psc)+4096*1.2


                        if y_center_px <= 235:
                            y_center_psc = int(y_center_px * px2psc)+4096*0.6
                            if x_center_px <= 230:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.0

                            elif 230 < x_center_px <= 320:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.5

                            elif 320 < x_center_px <= 420:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.15

                            elif 420 < x_center_px <= 500:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.7

                            elif 500 < x_center_px:
                                x_center_psc = int(x_center_px * px2psc)+4096*2.0
                                
                        elif 235 < y_center_px <= 335:
                            y_center_psc = int(y_center_px * px2psc)+4096*1.2
                            if x_center_px <= 230:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.0

                            elif 230 < x_center_px <= 320:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.65

                            elif 320 < x_center_px <= 420:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.15

                            elif 420 < x_center_px <= 500:
                                x_center_psc = int(x_center_px * px2psc)+4096*2.1

                            elif 500 < x_center_px:
                                x_center_psc = int(x_center_px * px2psc)+4096*2.4

                        elif 335 < y_center_px <= 480:
                            y_center_psc = int(y_center_px * px2psc)+4096*1.80
                            if x_center_px <= 230:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.0

                            elif 230 < x_center_px <= 320:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.65

                            elif 320 < x_center_px <= 420:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.3

                            elif 420 < x_center_px <= 500:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.65

                            elif 500 < x_center_px:
                                x_center_psc = int(x_center_px * px2psc)+4096*2.1

                        elif 480 < y_center_px:
                            y_center_psc = int(y_center_px * px2psc)+4096*2.4
                            if x_center_px <= 230:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.0

                            elif 230 < x_center_px <= 320:
                                x_center_psc = int(x_center_px * px2psc)+4096*0.55

                            elif 320 < x_center_px <= 420:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.05

                            elif 420 < x_center_px <= 500:
                                x_center_psc = int(x_center_px * px2psc)+4096*1.9

                            elif 500 < x_center_px:
                                x_center_psc = int(x_center_px * px2psc)+4096*2.1


                        x_psc1 = hex(int(x_center_psc/256))
                        x_psc2 = hex(int(x_center_psc%256))
                        y_psc1 = hex(int(y_center_psc/256))
                        y_psc2 = hex(int(y_center_psc%256))

                        # bbox = f"{xmin}  {ymin}  {xmax}  {ymax}"
                        detection_text = f"{class_id}, {labels} {x_center_px, y_center_px}, {x_psc1, x_psc2, y_psc1, y_psc2}"
                        detection_texts.append(detection_text)
                        
                        x1 = x_psc1
                        y1 = y_psc1
                        x2 = x_psc2
                        y2 = y_psc2

                        if labels == 'bottle' or labels == 'can':
                            R += 1
                            if R != 0 and R % 15 == 0:
                                kind = 0x01
                                PickUp = struct.pack('BBBB BBBB', 0x66, kind, int(x1,16), int(x2,16), int(y1,16), int(y2,16), angle, int(px2duo,16))
                                sent_command(PickUp)
                                H = 0
                                R = 0
                                K = 0
                                O = 0
                                print(f"0x66, {kind}, {x1}, {x2}, {y1}, {y2}, {angle}, {px2duo}, {x_length, y_length}\n{class_id}, {x_center_px, y_center_px}, {x_psc1, x_psc2, y_psc1, y_psc2, angle, px2duo}, {labels}")
                                # time.sleep(2)

                        elif labels == 'potato' or labels == 'turnip' or labels == 'carrot':
                            K += 1
                            if K != 0 and K % 15 == 0:
                                kind = 0x03
                                PickUp = struct.pack('BBBB BBBB', 0x66, kind, int(x1,16), int(x2,16), int(y1,16), int(y2,16), angle, int(px2duo,16))
                                sent_command(PickUp)
                                H = 0
                                R = 0
                                K = 0
                                O = 0
                                print(f"0x66, {kind}, {x1}, {x2}, {y1}, {y2}, {angle}, {px2duo}, {x_length, y_length}\n{class_id}, {x_center_px, y_center_px}, {x_psc1, x_psc2, y_psc1, y_psc2, angle, px2duo}, {labels}")
                                # time.sleep(2)
                        
                        elif labels == 'battery':
                            H += 1
                            if H != 0 and H % 15 == 0:
                                kind = 0x02
                                PickUp = struct.pack('BBBB BBBB', 0x66, kind, int(x1,16), int(x2,16), int(y1,16), int(y2,16), angle, int(px2duo,16))
                                sent_command(PickUp)
                                H = 0
                                R = 0
                                K = 0
                                O = 0
                                print(f"0x66, {kind}, {x1}, {x2}, {y1}, {y2}, {angle}, {px2duo}, {x_length, y_length}\n{class_id}, {x_center_px, y_center_px}, {x_psc1, x_psc2, y_psc1, y_psc2, angle, px2duo}, {labels}")
                                # time.sleep(2)
                        
                        elif labels == 'stone' or labels == 'brick' or labels == 'chip' :
                            O += 1
                            if O != 0 and O % 15 == 0:
                                kind = 0x04
                                PickUp = struct.pack('BBBB BBBB', 0x66, kind, int(x1,16), int(x2,16), int(y1,16), int(y2,16), angle, int(px2duo,16))
                                sent_command(PickUp)
                                H = 0
                                R = 0
                                K = 0
                                O = 0
                                print(f"0x66, {kind}, {x1}, {x2}, {y1}, {y2}, {angle}, {px2duo}, {x_length, y_length}\n{class_id}, {x_center_px, y_center_px}, {x_psc1, x_psc2, y_psc1, y_psc2, angle, px2duo}, {labels}")
                                # time.sleep(2)
                    
                    elif max_num == 1:
                        if labels == 'battery' or labels == 'drug' or labels == 'pill':
                            H += 1
                            self.kind = 0x02
                            if H % 15 == 0:
                                self.cont += 1
                                sent_command(Harmful)
                                R = -8
                                H = -20
                                K = -12
                                O = -16
                                text = f'{self.cont} 有害垃圾 1 OK!'
                                self.text_processed.emit(text)
                                print("Harmful sent")

                        if labels == 'bottle' or labels == 'can':
                            R += 1
                            self.kind = 0x01
                            if R % 15 == 0:
                                self.cont += 1
                                sent_command(Recycle)
                                text = f'{self.cont} 可回收垃圾 1 OK!'
                                R = -8
                                H = -20
                                K = -12
                                O = -16
                                self.text_processed.emit(text)
                                print("Recycle sent")
                                # self.Max_Com()

                        if labels == 'potato' or labels == 'carrot' or labels == 'turnip':
                            K += 1
                            self.kind = 0x03
                            if K % 15 == 0:
                                self.cont += 1
                                sent_command(Kitchen)
                                R = -8
                                H = -20
                                K = -12
                                O = -16
                                text = f'{self.cont} 厨余垃圾 1 OK!'
                                self.text_processed.emit(text)
                                print("Kitchen sent")

                        if labels == 'stone' or labels == 'chip' or labels == 'brick':
                            O += 1
                            self.kind = 0x04
                            if O % 15 == 0:
                                self.cont += 1
                                sent_command(Others)
                                R = -8
                                H = -20
                                K = -12
                                O = -16
                                text = f'{self.cont} 其他垃圾 1 OK!'
                                self.text_processed.emit(text)
                                print("Others sent")
                        

                self.text_processed.emit("\n".join(detection_texts))    # 合并发送所有检测信息
                # print(len(detection_texts))
                # print(f"R:{R}, H:{H}, K:{K}, O:{O}")

                # time.sleep(0.01)
                

t=0

class SerialThread(QThread):
    serial_data_received = pyqtSignal(int)

    def __init__(self):
        super().__init__()

    def run(self):
        global t
        while True:
            # t+=1
            # print(f"time: {t}s")
            # if t % 280 == 0:
            #     sent_command(Others)
            received_value = read_mess()
            self.serial_data_received.emit(received_value)
            self.msleep(1000)  # 休眠1秒钟，可以根据需要调整


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.model = torch.hub.load("./", "custom", path="m_Final_v25.pt", source='local')
        self.model.conf = 0.7
        self.model.iou = 0.3
        self.output_mess = self.findChild(QTextEdit, "output_mess")
        self.maxdet_mess = self.findChild(QTextEdit, "maxdet_mess")

        self.video_thread = VideoThread(self.model)
        self.video_thread.frame_processed.connect(self.update_realtime_det)
        self.video_thread.text_processed.connect(self.show_mess)
        self.video_thread.maxdet_triggered.connect(self.show_maxdet_mess)

        self.video_thread.start()

        self.timer = QTimer()
        self.timer.setInterval(1)
        self.timer.timeout.connect(self.open_video)
        self.det = None

        self.text_style()
        self.video_show()

        self.serial_thread = SerialThread()
        self.serial_thread.serial_data_received.connect(self.handle_serial_data)
        self.serial_thread.start()

    def handle_serial_data(self, received_value):
        # print(f"Received value: 0x{received_value:02X}")  # 打印接收到的十六进制值
        if received_value == 0x11:
            print(f"Received value: 0x{received_value:02X}")  # 打印接收到的十六进制值
            self.show_maxdet_mess()
        elif received_value == 0x99:
            pass
            # sent_command(MaxDet)
            # print("MaxDet sent")

    def open_video(self):
        ret, frame = self.video.read()
        if not ret:
            print("Error: Unable to read frame.")
            self.timer.stop()
        else:
            frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
            self.video_player.setPixmap(QPixmap.fromImage(convert2QImage(frame)))

    def video_show(self):
        self.video = cv.VideoCapture('./1_1.mp4')
        if not self.video.isOpened():
            print("Error: Unable to open mp4.")
            return
        else:
            self.timer.start()

    def show_mess(self, text):
        self.output_mess.setText(text)

    def text_style(self):
        styleSheet = "QTextEdit{font-size: 50px; color: rgb(100, 200, 0);}"
        maxdet_mess_styleSheet = "QTextEdit{font-size: 50px; color: rgb(255, 0, 0); text-align: center;}"
        self.output_mess.setStyleSheet(styleSheet)
        self.maxdet_mess.setStyleSheet(maxdet_mess_styleSheet)

    def update_realtime_det(self, image):
        self.realtime_det.setPixmap(QPixmap.fromImage(image))

    def show_maxdet_mess(self):
        # self.maxdet_mess.setPlainText("75%满载预警")  # 使用setPlainText设置文本
        self.maxdet_mess.setText("75%满载预警")  # 使用setPlainText设置文本

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()
